package com.bfxy.disruptor.common.waitStraty;

import java.util.concurrent.locks.LockSupport;

import com.bfxy.disruptor.common.balance.Sequence;
import com.bfxy.disruptor.common.balance.SequenceBarrier;
import com.bfxy.disruptor.common.exception.AlertException;

//无锁的方式,多次循环尝试不成功后，选择让出CPU，等待下次调度，多次调度后仍不成功，尝试前睡眠一个纳秒级别的时间再尝试。这种策略平衡了延迟和CPU资源占用，但延迟不均匀。
public final class SleepingWaitStrategy implements WaitStrategy {
	private static final int DEFAULT_RETRIES = 200;

	private final int retries;// 200

	public SleepingWaitStrategy() {
		this(DEFAULT_RETRIES);
	}

	public SleepingWaitStrategy(int retries) {
		this.retries = retries;
	}

	@Override
	public long waitFor(final long sequence, Sequence cursor, final Sequence dependentSequence,
			final SequenceBarrier barrier) throws AlertException, InterruptedException {
		long availableSequence;
		int counter = retries;// 每次调用这个方法，counter从200开始

		while ((availableSequence = dependentSequence.get()) < sequence) {
			counter = applyWaitMethod(barrier, counter);// 空循环，一直等着
		}

		return availableSequence;
	}

	@Override
	public void signalAllWhenBlocking() {
	}

	private int applyWaitMethod(final SequenceBarrier barrier, int counter) throws AlertException {
		barrier.checkAlert();

		if (counter > 100)// 大于100就一直减1
		{
			--counter;
		} else if (counter > 0) {
			--counter;
			// 让出时间片一会，有可能下一个还是自己执行
			Thread.yield();
			// 线程让步。就是说当一个线程使用了这个方法之后，它就会把自己CPU执行的时间让掉，
			// 让自己或者其它的线程运行，注意是让自己或者其他线程运行，并不是单纯的让给其他线程。
			// 它能让当前线程由“运行状态”进入到“就绪状态”，从而让其它具有相同优先级的等待线程获取执行权；但是，并不能保
			// 证在当前线程调用yield()之后，其它具有相同优先级的线程就一定能获得执行权；也有可能是当前线程又进入到“运行状态”继续运行！
			 
			  //但是线程是有优先级的，优先级越高的人，就一定能第一个上车吗？这是不一定的，优先级高的人仅仅只是第一个上车的概率大了一点而已，
			  //最终第一个上车的，也有可能是优先级最低的人。并且所谓的优先级执行，是在大量执行次数中才能体现出来的。
			 
		} else {
			LockSupport.parkNanos(1L);// 挂起当前线程
		}
		return counter;
	}
}
